package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.constants.message.PublishArticleConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wenmedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Value("${file.oss.web-site}")
    String webSite;

    /**
     * 自动审核方法
     *
     * @param wmNewsId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void autoScanWmNews(Integer wmNewsId) {
        log.info(" 自动审核发布方法 被调用   当前审核发布的文章id==> {}", wmNewsId);
        //1. 根据文章id 远程调用feign查询文章
        if (wmNewsId == null) {
            log.error("自动审核文章失败    文章id为空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = wmNewsMapper.selectById(wmNewsId);
        if (wmNews == null) {
            log.error("自动审核文章失败    未查询自媒体文章信息  wmNewsId:{}", wmNewsId);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //先抽取文章中所有的文本内容和图片内容 map(content:文本内容,images:图片合集) string list<string>
        Map<String, Object> textAndImageMap = handleTextAndImages(wmNews);
        //  使用自管理敏感词 进行敏感词审核    2 未通过    有敏感词  false    无 true
        boolean isSensitive = handleSensitive(textAndImageMap.get("content").toString(), wmNews);
        if (!isSensitive) {
            log.error("文章自动审核失败   文章中包含敏感词 文章id:{}", wmNewsId);
            return;
        }
        //  使用阿里云内容安全进行文本审核   2 未通过   3 带人工审核    违规 false  通过 true
        boolean isTextScan = handleTextScan(textAndImageMap.get("content").toString(), wmNews);
        if (!isTextScan) {
            log.error("文章自动审核失败   文章中包含违规信息 文章id:{}", wmNewsId);
            return;
        }
        //  使用阿里云内容安全进行图片审核   2 未通过   3 带人工审核
        List<String> images = (List<String>) textAndImageMap.get("images");
        if (CollectionUtils.isNotEmpty(images)) {
            boolean isImageScan = handleImageScan(images, wmNews);
            if (!isImageScan) {
                log.error("文章自动审核失败   文章图片中 包含违规信息 文章id:{}", wmNewsId);
                return;
            }
        }
        //  将文章的状态修改 为 8   自动审核通过
        updateWmNews(wmNews, WmNews.Status.SUCCESS.getCode(), "审核通过");
        //通知定时发送文章
        //1.获取发送的时间
        long publishTime = wmNews.getPublishTime().getTime();
        //2.获取当前时间
        long currentTimeMillis = System.currentTimeMillis();
        //3.时间差
        long remainTime = publishTime - currentTimeMillis;
        //4.发消息
        rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE, PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY,
                wmNews.getId(),
                message -> {
                    (message).getMessageProperties().setHeader("x-delay",remainTime<=0?0:remainTime);
                    return message;

        });


    }

    @Autowired
    GreenImageScan greenImageScan;

    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean isFlag = true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    isFlag = false;
                    updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "图片中包含违规内容");
                    break;
                case "review":
                    isFlag = false;
                    updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "图片中有不确定的信息，需要进一步人工审核");
                    break;
                default:
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 将状态修改为 3    带人工审核
            log.error(" 阿里云文本内容安全接口调用失败");
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云图片内容安全接口调用失败,转为人工审核");
            isFlag = false;
        }
        return isFlag;
    }

    @Autowired
    GreenTextScan greenTextScan;

    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean isFlag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    isFlag = false;
                    // TODO  可以扩展 返回具体为什么违规的信息
                    updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本中包含违规内容");
                    break;
                case "review":
                    isFlag = false;
                    updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文本中有不确定的信息，需要进一步人工审核");
                    break;
                default:
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 将状态修改为 3    带人工审核
            log.error(" 阿里云文本内容安全接口调用失败");
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云文本内容安全接口调用失败,转为人工审核");
            isFlag = false;
        }
        return isFlag;
    }

    @Autowired
    AdminFeign adminFeign;

    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean isFlag = true;
        // 1. 查询出敏感词列表
        ResponseResult<List<String>> sensitivesResult = adminFeign.selectAllChannel();
        if (!sensitivesResult.checkCode()) {
            log.error("自动审核失败  原因远程调用敏感词数据失败");
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, "远程调用查询敏感词失败");
        }
        List<String> sensitives = sensitivesResult.getData();
        if (CollectionUtils.isNotEmpty(sensitives)) {
            // 2. 基于DFA工具类生成数据模型
            SensitiveWordUtil.initMap(sensitives);
            // 3. 基于DFA检测是否包含敏感词
            Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
            // 4. 如果有敏感词词  将wmNews状态修改为2
            if (map != null && map.size() > 0) {
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本中包含敏感词: " + map);
                isFlag = false;
            }
        }
        return isFlag;
    }

    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 抽取文章中所有的文本内容和图片路劲合计
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
//获取文章内容转为
        // 1. 获取文章内容  并转为 List<Map> 集合
        List<Map> contentMapList = JSON.parseArray(wmNews.getContent(), Map.class);
        // 2. 拼接文本内容 [{type:text,value: "  家乡好美"}]  + title   国家伟大       家乡好美_hmtt_国家伟大
        String content = contentMapList.stream()
                // 筛选内容中 所有文本内容
                .filter(m -> "text".equals(m.get("type")))
                // 获取文本类型map中的文本内容
                .map(m -> m.get("value").toString())
                // 将所有文本拼接成一个大的字符串
                .collect(Collectors.joining("_hmtt_"));
        content += "_hmtt_" + wmNews.getTitle();
        // 3. 拼接图片路径集合
        List<String> images = contentMapList.stream()
                // 筛选内容中 所有文本内容
                .filter(m -> "image".equals(m.get("type")))
                // 获取文本类型map中的图片路径(全路径)
                .map(m -> m.get("value").toString())
                // 将所有文本拼接成一个大的字符串
                .collect(Collectors.toList());
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            // url1,url2,url3 => 切割 返回数组 ==> stream .map(加前缀) .collect 集合
            List<String> coverUrlList = Arrays.stream(wmNews.getImages().split(","))
                    .map(url -> webSite + url)
                    .collect(Collectors.toList());
            images.addAll(coverUrlList);
        }
        images = images.stream().distinct().collect(Collectors.toList());
        // 4. 存入map并返回
        Map<String, Object> result = new HashMap<>(2);
        result.put("content", content);
        result.put("images", images);
        return result;
    }
}